package com.onpositive.simple.persistance;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.ArrayDeque;
import java.util.BitSet;


public class FSRecordStorage extends RecordStorage {
	
	final static int intSize = 4 ;	
	File file ;
	ByteBuffer byteBuffer ;
	IntBuffer intBuffer ;
	private RandomAccessFile recordStorage ;
	
	protected int recordsCount, recordsArrayOffset = 2*intSize ;
	
	private ArrayDeque<Integer> emptyCells ;
	private BitSet deletedFlag ; 

	public FSRecordStorage( String path )
	{
		String filename = path + "recStorage.dat" ;
		
		
		file = new File( filename ) ;
		try {
			recordStorage = new RandomAccessFile( file, "rws" ) ;
			recordStorage.setLength(0);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		emptyCells = new ArrayDeque<Integer>() ;
		deletedFlag = new BitSet() ;
		recordsCount = 0 ;
	}
	@Override
	public void init()
	{
		byteBuffer = ByteBuffer.allocate( intSize*recordLength ) ;
		intBuffer = byteBuffer.asIntBuffer() ;
		intBuffer.clear() ;
		intBuffer.put(recordLength) ;
		intBuffer.put(0) ;
		byte initialParams[] = new byte[2*intSize] ;
		byteBuffer.get( initialParams, 0, 2*intSize ) ;
		try {
			recordStorage.seek(0) ;
			recordStorage.write( initialParams, 0, 2*intSize ) ;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}
	public void updateRecordsCount(){
		
		byteBuffer.clear() ;
		intBuffer.clear() ;
		intBuffer = byteBuffer.asIntBuffer() ;
		intBuffer.put(recordLength) ;
		
		byte initialParams[] = new byte[intSize] ; 
		byteBuffer.get(initialParams,0,intSize) ;
		try {
			recordStorage.seek(intSize) ;
			recordStorage.write( initialParams, 0, intSize) ;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	@Override
	public int putRecord( int[] record) {
		
		int id = getVacantId() ;
		
		deletedFlag.set( id, false ) ;
		recordsCount++ ;
		updateRecordsCount() ;
		putRecord(record, id) ;		
		
		return id ;
		
	}
	
	@Override
	protected int getVacantId()
	{
		Integer emptyCell = emptyCells.pollFirst() ;
		
		if ( emptyCell == null ){
			emptyCell = recordsCount ;
			try {
				if( recordStorage.length() < (recordsCount+1)*intSize*recordLength )
					reallocateStorage((recordsCount+1)*intSize*recordLength) ;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		return emptyCell ;
	}	
	
	@Override
	protected void putRecord( int[] record, int id )
	{
		intBuffer.clear() ;
		byteBuffer.clear();
		
		
		for( int i = 0 ; i < recordLength ; i++ )
			intBuffer.put( record[i]) ;

		byte content[] = new byte[ intSize*recordLength ] ;
		byteBuffer.get(content,0,intSize*recordLength) ;
		try {
			recordStorage.seek(recordsArrayOffset + intSize*recordLength*id) ;
			recordStorage.write( content, 0 , intSize*recordLength ) ;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
		
	@Override
	public int[] getRecord(int id) {
		
		if( !deletedFlag.get(id) ){
			
			intBuffer.clear() ;
			byteBuffer.clear();
			
			byte content[] = new byte[ intSize*recordLength ] ;
			try {
				recordStorage.seek(recordsArrayOffset + intSize*recordLength*id) ;
				recordStorage.read( content, 0, intSize*recordLength ) ;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			byteBuffer.put(content) ;
			
			int record[] = new int[recordLength] ;
			intBuffer.get(record, 0, intSize*recordLength) ;
			
			return record ;	
		}
			
					
		return null;
	}
	
	@Override
	public void deleteRecord(int id) {
		
	}
	private void reallocateStorage(int requiredLength) {


		long length ;
		try {
			length = (int) recordStorage.length() ;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			length = 1 ;
		}
		
		for (  ; length < requiredLength ; )
			length = (long)(length * 1.4 + 1) ;
		
		try {
			recordStorage.setLength(length) ;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		
	}


	



	
}
